/**
 * 
 */
package com.pxingg.algorithm;


import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import com.pxingg.Constants;

/**
 * @author pxingg
 * 
 */
public class ByteArrayQueueTest
{
    /**
     * @throws java.lang.Exception
     */
    @BeforeClass
    public static void setUpBeforeClass() throws Exception
    {
    }

    /**
     * @throws java.lang.Exception
     */
    @AfterClass
    public static void tearDownAfterClass() throws Exception
    {
    }

    /**
     * 测试时QUEUE的长度
     */
    final int TEST_QUEUE_LENGTH = 8;

    /**
     * 测试所使用的队列
     */
    ByteArrayQueue queue = new ByteArrayQueue(TEST_QUEUE_LENGTH);

    /**
     * @throws java.lang.Exception
     */
    @Before
    public void setUp() throws Exception
    {
        queue.clear();
    }

    /**
     * @throws java.lang.Exception
     */
    @After
    public void tearDown() throws Exception
    {
    }

    /**
     * Test method for {@link com.pxingg.algorithm.ByteArrayQueue#append(byte)}.
     */
    @Test
    public final void testAppendByte()
    {
        queue.append((byte) 10);
        byte[] data = queue.retrieve(1);
        Assert.assertEquals((byte) 10, data[0]);
        // 把队列填充快满的位置
        queue.clear();
        for (int i = 0; i < TEST_QUEUE_LENGTH - 2; i++)
        {
            queue.append((byte) 01);
        }
        Assert.assertTrue(queue.append((byte) 01));
        Assert.assertTrue(queue.append((byte) 01));
        // 队列已经满了，这两个数据不能再添加了
        Assert.assertFalse(queue.append((byte) 01));
        Assert.assertFalse(queue.append((byte) 01));

        // 把队列填充快满的位置
        queue.clear();
        for (int i = 0; i < TEST_QUEUE_LENGTH - 2; i++)
        {
            queue.append((byte) 01);
        }
        // 移除前面数据
        queue.serve(TEST_QUEUE_LENGTH - 2);

        // 填充致数组满
        queue.append((byte) 10);
        queue.append((byte) 11);
        data = queue.retrieve(2);
        final byte[] expect = {
            (byte) 10, (byte) 11
        };
        Assert.assertArrayEquals(expect, data);
        Assert.assertEquals(2, queue.size());

        // 满了之后，再次填充数据
        queue.append((byte) 12);
        queue.append((byte) 13);
        data = queue.retrieve(4);
        final byte[] expect2 = {
            (byte) 10, (byte) 11, (byte) 12, (byte) 13
        };
        Assert.assertArrayEquals(expect2, data);
        Assert.assertEquals(4, queue.size());
    }

    /**
     * Test method for {@link com.pxingg.algorithm.ByteArrayQueue#append(byte[])} .
     */
    @Test
    public final void testAppendByteArray()
    {
        final byte[] data = {
            (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5
        };
        queue.append(data);
        Assert.assertEquals(5, queue.size());
        Assert.assertArrayEquals(data, queue.retrieve(5));
        Assert.assertFalse(queue.append(data));
        Assert.assertEquals(5, queue.size());
        final byte data2[] = {
            (byte) 6, (byte) 7, (byte) 8
        };
        queue.append(data2);
        Assert.assertEquals(8, queue.size());
        queue.serve(queue.size());

        queue.append(data);
        Assert.assertArrayEquals(data, queue.serve(5));
        queue.append(data);
        Assert.assertArrayEquals(data, queue.serve(5));
    }

    /**
     * Test method for {@link com.pxingg.algorithm.ByteArrayQueue#append(byte[], int)}.
     */
    @Test
    public final void testAppendByteArrayInt()
    {
        final byte[] data = {
            (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5
        };
        queue.append(data, 5);
        Assert.assertEquals(5, queue.size());
        Assert.assertArrayEquals(data, queue.retrieve(5));

        queue.append(data, 3);
        Assert.assertEquals(8, queue.size());
        Assert.assertArrayEquals(data, queue.serve(5));
    }

    /**
     * Test method for {@link com.pxingg.algorithm.ByteArrayQueue#ByteArrayQueue()}.
     */
    @Test
    public final void testByteArrayQueue()
    {
        final ByteArrayQueue queue2 = new ByteArrayQueue();
        Assert.assertEquals(Constants.DEFAULT_MESSAGE_BUFFER_LENGTH, queue2.capacity);
        Assert.assertEquals(Constants.DEFAULT_MESSAGE_BUFFER_LENGTH, queue2.currentCapacity());
    }

    /**
     * Test method for {@link com.pxingg.algorithm.ByteArrayQueue#ByteArrayQueue(int)}.
     */
    @Test
    public final void testByteArrayQueueInt()
    {
        final ByteArrayQueue queue2 = new ByteArrayQueue(TEST_QUEUE_LENGTH);
        Assert.assertEquals(TEST_QUEUE_LENGTH, queue2.capacity);
        Assert.assertEquals(TEST_QUEUE_LENGTH, queue2.currentCapacity());
    }

    /**
     * Test method for {@link com.pxingg.algorithm.ByteArrayQueue#clear()}.
     */
    @Test
    public final void testClear()
    {
        queue.append((byte) 10);
        Assert.assertEquals(1, queue.size());
        queue.clear();
        Assert.assertEquals(0, queue.size());
    }

    /**
     * Test method for {@link com.pxingg.algorithm.ByteArrayQueue#currentCapacity()}.
     */
    @Test
    public final void testCurrentCapacity()
    {
        int currentCapacity = TEST_QUEUE_LENGTH;
        for (int i = 0; i < TEST_QUEUE_LENGTH; i++)
        {
            queue.append((byte) 10);
            currentCapacity--;
            Assert.assertEquals(currentCapacity, queue.currentCapacity());
        }

        // 队列满的时候，不能再操作数据
        Assert.assertFalse(queue.append((byte) 10));

        final byte[] data = {
            (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5
        };
        Assert.assertFalse(queue.append(data));
    }

    /**
     * Test method for {@link com.pxingg.algorithm.ByteArrayQueue#empty()}.
     */
    @Test
    public final void testEmpty()
    {

        Assert.assertTrue(queue.empty());
    }

    /**
     * Test method for {@link com.pxingg.algorithm.ByteArrayQueue#full()}.
     */
    @Test
    public final void testFull()
    {
        Assert.assertTrue(queue.empty());
        for (int i = 0; i < TEST_QUEUE_LENGTH; i++)
        {
            queue.append((byte) 10);
        }
        Assert.assertTrue(queue.full());
    }

    /**
     * Test method for {@link com.pxingg.algorithm.ByteArrayQueue#getCapacity()} .
     */
    @Test
    public final void testGetCapacity()
    {
        Assert.assertEquals(TEST_QUEUE_LENGTH, queue.getCapacity());
    }

    /**
     * Test method for {@link com.pxingg.algorithm.ByteArrayQueue#retrieve(int)} .
     */
    @Test
    public final void testRetrieve()
    {
        final byte[] data = {
            (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5
        };
        queue.append(data, 5);
        Assert.assertEquals(5, queue.size());
        Assert.assertEquals(null, queue.serve(100));
        Assert.assertArrayEquals(data, queue.retrieve(5));
        Assert.assertEquals(null, queue.serve(100));
        Assert.assertArrayEquals(data, queue.retrieve(5));
    }

    /**
     * Test method for {@link com.pxingg.algorithm.ByteArrayQueue#serve(int)}.
     */
    @Test
    public final void testServe()
    {
        final byte[] data = {
            (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5
        };
        final byte data2[] = {
            (byte) 6, (byte) 7, (byte) 8
        };
        queue.append(data, 5);
        queue.append(data2, 3);
        Assert.assertEquals(8, queue.size());
        Assert.assertEquals(null, queue.serve(100));
        Assert.assertArrayEquals(data, queue.serve(5));
        Assert.assertEquals(null, queue.serve(100));
        Assert.assertArrayEquals(data2, queue.serve(3));

        // 这是队列已经用过一次，在使用一次
        queue.append(data, 5);
        queue.append(data2, 3);
        Assert.assertEquals(8, queue.size());
        Assert.assertEquals(null, queue.serve(100));
        Assert.assertArrayEquals(data, queue.serve(5));
        Assert.assertEquals(null, queue.serve(100));
        Assert.assertArrayEquals(data2, queue.serve(3));
    }

    /**
     * Test method for {@link com.pxingg.algorithm.ByteArrayQueue#serveUntill(byte)}.
     */
    @Test
    public final void testServeUntill()
    {
        final byte[] data = {
            (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5
        };
        final byte data2[] = {
            (byte) 6, (byte) 7, (byte) 8
        };
        final byte data3[] = {
            (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7
        };
        final byte[] data4 = {
            (byte) 8, (byte) 1, (byte) 2, (byte) 3, (byte) 4
        };
        final byte[] data5 = {
            (byte) 5
        };

        queue.append(data, data.length);
        Assert.assertEquals(data.length, queue.size());
        Assert.assertEquals(null, queue.serveUntill((byte) 7));

        queue.append(data2, data2.length);
        Assert.assertArrayEquals(data3, queue.serveUntill((byte) 7));

        queue.append(data, data.length);
        Assert.assertArrayEquals(data4, queue.serveUntill((byte) 4));
        Assert.assertArrayEquals(data5, queue.serveUntill((byte) 5));
        // 数据已经全部用完，上面的操作再进行一次
        queue.append(data, data.length);
        Assert.assertEquals(data.length, queue.size());
        Assert.assertEquals(null, queue.serveUntill((byte) 7));

        queue.append(data2, data2.length);
        Assert.assertArrayEquals(data3, queue.serveUntill((byte) 7));

        queue.append(data, data.length);
        Assert.assertArrayEquals(data4, queue.serveUntill((byte) 4));
        Assert.assertArrayEquals(data5, queue.serveUntill((byte) 5));
    }

    /**
     * Test method for {@link com.pxingg.algorithm.ByteArrayQueue#size()}.
     */
    @Test
    public final void testSize()
    {
        for (int i = 0; i < TEST_QUEUE_LENGTH; i++)
        {
            queue.append((byte) 10);
            Assert.assertEquals(i + 1, queue.size());
        }
    }

    /**
     * Test method for {@link com.pxingg.algorithm.ByteArrayQueue#tryRetrieve(int)}.
     */
    @Test
    public final void testTryRetrieve()
    {
        final byte[] data = {
            (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5
        };
        final byte data2[] = {
            (byte) 6, (byte) 7, (byte) 8
        };
        final byte data3[] = {
            (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8
        };

        queue.clear();
        queue.append(data, 5);
        Assert.assertEquals(data.length, queue.size());
        Assert.assertArrayEquals(data, queue.tryRetrieve(100));
        queue.append(data2, 3);
        Assert.assertEquals(data2.length + data.length, queue.size());
        Assert.assertArrayEquals(data3, queue.tryRetrieve(100));
        // 这是队列已经用过一次，在使用一次
        queue.clear();
        queue.append(data, 5);
        Assert.assertEquals(data.length, queue.size());
        Assert.assertArrayEquals(data, queue.tryRetrieve(100));
        queue.append(data2, 3);
        Assert.assertEquals(data2.length + data.length, queue.size());
        Assert.assertArrayEquals(data3, queue.tryRetrieve(100));
    }

    /**
     * Test method for {@link com.pxingg.algorithm.ByteArrayQueue#tryServe(int)}.
     */
    @Test
    public final void testTryServe()
    {
        final byte[] data = {
            (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5
        };
        final byte data2[] = {
            (byte) 6, (byte) 7, (byte) 8
        };

        queue.append(data, 5);
        Assert.assertEquals(data.length, queue.size());
        Assert.assertArrayEquals(data, queue.tryServe(100));
        queue.append(data2, 3);
        Assert.assertEquals(data2.length, queue.size());
        Assert.assertArrayEquals(data2, queue.tryServe(100));
        // 这是队列已经用过一次，在使用一次
        queue.append(data, 5);
        Assert.assertEquals(data.length, queue.size());
        Assert.assertArrayEquals(data, queue.tryServe(100));
        queue.append(data2, 3);
        Assert.assertEquals(data2.length, queue.size());
        Assert.assertArrayEquals(data2, queue.tryServe(100));
    }
}
